package com.qth.valet.common.netty;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.qth.valet.common.utils.ResponseResult;
import com.qth.valet.common.utils.StatusConstants;
import com.qth.valet.entity.po.Driver;
import com.qth.valet.entity.po.Orders;
import com.qth.valet.service.DriversService;
import com.qth.valet.service.OrdersService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
@RequiredArgsConstructor
@ChannelHandler.Sharable
public class WebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static final ConcurrentHashMap<Integer, Channel> driverChannel = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<String, Integer> channelDriver = new ConcurrentHashMap<>();

    private final DriversService driversService;

    private final OrdersService ordersService;

    @Value("${order.min-insurance-amount}")
    private Integer minInsuranceAmount;

    //private final DriverOrderService driverOrderService;

    //private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    //private static final ChannelGroup CHANNELS = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /*static {
        // 启动定时推送任务（每5秒推送一次当前时间）
        scheduler.scheduleAtFixedRate(() -> {
            //String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            //String message = "{\"type\":\"time\",\"data\":\"" + time + "\"}";
            // 向所有连接的客户端广播消息
            CHANNELS.writeAndFlush(new TextWebSocketFrame("hi"));
        }, 0, 5, TimeUnit.SECONDS);
    }*/

    // 客户端连接建立时触发
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        log.info("新客户端连接：{}", channel.id().asShortText());
        //CHANNELS.add(channel);

        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new Message<>(Message.INIT, "连接建立成功"))));
    }

    // 客户端断开连接时触发
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        Integer id = channelDriver.get(channel.id().asShortText());
        if(id != null){
            driversService.removeDriverAddr(id);
            driversService.updateSts(id, StatusConstants.DRIVER_OFFLINE);
            log.info("司机断开连接：{}", id);
        }
    }

    // 接收客户端消息时触发
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
        log.info("收到客户端消息：{}", msg.text());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws InterruptedException {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            WebSocketServerProtocolHandler.HandshakeComplete complete = (WebSocketServerProtocolHandler.HandshakeComplete) evt;
            String url = complete.requestUri();
            // 传过来的司机信息
            Driver driver = getDriver(url);
            if (driver != null) {
                // 查询数据库司机信息
                Driver dbDriver = driversService.getById(driver.getId());
                if (dbDriver == null) {
                    ctx.close();
                    return;
                }

                // 判断司机是否有正在进行中的订单
                List<Orders> orders = ordersService.checkDriverOnline(driver.getId());
                if (orders.isEmpty()) {
                    // 判断司机余额是否充足
                    if (dbDriver.getAccountBalance() < minInsuranceAmount) {
                        String msgStr = JSON.toJSONString(new Message<>(Message.PLEASE_RECHARGE, "您的账户余额不足，请充值后再抢单"));
                        ctx.channel().writeAndFlush(new TextWebSocketFrame(msgStr));
                        Thread.sleep(100L);
                        ctx.close();
                    } else {
                        log.info("司机{}上线", driver.getId());
                        driversService.setDriverAddr(driver);
                        driversService.updateSts(driver.getId(), StatusConstants.DRIVER_ONLINE);

                        driverChannel.put(driver.getId(), ctx.channel());
                        channelDriver.put(ctx.channel().id().asShortText(), driver.getId());

                        ordersService.selectDriverBySchedule();
                    }
                } else {
                    log.info("司机{}已有在执行的订单", driver.getId());
                    ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new Message<>(Message.DRIVING, "你已有在执行的订单"))));
                    Thread.sleep(100L);
                    ctx.close();
                }
            }
        }
    }

    //发送订单消息给司机
    public void sendMsg(Integer id, String orderId) {
        log.info("发送订单{}消息给司机{}", orderId, id);
        Channel channel = driverChannel.get(id);
        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(new Message<>(Message.SEND_ORDER, orderId))));
        channel.close();
    }

    // 发生异常时触发
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error("连接异常：{}", cause.getMessage());
        ctx.close();
    }

    private Driver getDriver(String url) {
        Driver driver = new Driver();
        if (url == null || !url.contains("?")) {
            return null;
        }
        String[] urlArray = url.split("\\?");
        if (urlArray.length != 2) {
            return null;
        }

        String[] param = urlArray[1].split("&");
        for (String p : param) {
            String[] keyAndVal = p.split("=");
            if (keyAndVal.length != 2) {
                return null;
            }
            if (!"".equals(keyAndVal[0]) && "token".equals(keyAndVal[0])) {
                String loginIdStr = (String) StpUtil.getLoginIdByToken(keyAndVal[1]);
                int driverId = Integer.parseInt(loginIdStr);
                driver.setId(driverId);
            } else if (!"".equals(keyAndVal[0]) && "la".equals(keyAndVal[0])) {
                driver.setLa(Double.valueOf(keyAndVal[1]));
            } else if (!"".equals(keyAndVal[0]) && "lo".equals(keyAndVal[0])) {
                driver.setLo(Double.valueOf(keyAndVal[1]));
            }
        }

        return driver;
    }

}
